// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/arc/start_smart_selection_action_menu.h"

#include <algorithm>
#include <string>
#include <utility>

#include "base/bind.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/intent_util.h"
#include "chrome/browser/apps/app_service/launch_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/grit/generated_resources.h"
#include "components/renderer_context_menu/render_view_context_menu_proxy.h"
#include "content/public/browser/context_menu_params.h"
#include "ui/base/layout.h"
#include "ui/base/models/image_model.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/image/image_skia_operations.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/components/arc/metrics/arc_metrics_constants.h"
#endif

namespace arc {

namespace {

apps::mojom::IntentPtr CreateIntent(
    arc::TextSelectionActionDelegate::IntentInfo arc_intent,
    arc::TextSelectionActionDelegate::ActivityName activity) {
  auto intent = apps::mojom::Intent::New();
  intent->action = std::move(arc_intent.action);
  intent->data = std::move(arc_intent.data);
  intent->mime_type = std::move(arc_intent.type);
  intent->categories = std::move(arc_intent.categories);
  intent->ui_bypassed = arc_intent.ui_bypassed
                            ? apps::mojom::OptionalBool::kTrue
                            : apps::mojom::OptionalBool::kFalse;
  intent->extras = std::move(arc_intent.extras);

  intent->activity_name = std::move(activity.activity_name);

  return intent;
}

}  // namespace

// The maximum number of smart actions to show.
constexpr size_t kMaxMainMenuCommands = 5;

StartSmartSelectionActionMenu::StartSmartSelectionActionMenu(
    content::BrowserContext* context,
    RenderViewContextMenuProxy* proxy,
    std::unique_ptr<TextSelectionActionDelegate> delegate)
    : context_(context), proxy_(proxy), delegate_(std::move(delegate)) {}

StartSmartSelectionActionMenu::~StartSmartSelectionActionMenu() = default;

void StartSmartSelectionActionMenu::InitMenu(
    const content::ContextMenuParams& params) {
  const std::string converted_text = base::UTF16ToUTF8(params.selection_text);
  if (converted_text.empty())
    return;

  DCHECK(delegate_);
  if (!delegate_->RequestTextSelectionActions(
          converted_text, ui::GetSupportedResourceScaleFactors().back(),
          base::BindOnce(
              &StartSmartSelectionActionMenu::HandleTextSelectionActions,
              weak_ptr_factory_.GetWeakPtr()))) {
    return;
  }
#if BUILDFLAG(IS_CHROMEOS_ASH)
  // TODO(crbug.com/1275075): Take metrics in Lacros as well.
  base::RecordAction(base::UserMetricsAction("Arc.SmartTextSelection.Request"));
#endif

  // Add placeholder items.
  for (size_t i = 0; i < kMaxMainMenuCommands; ++i) {
    proxy_->AddMenuItem(IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 + i,
                        /*title=*/std::u16string());
  }
}

bool StartSmartSelectionActionMenu::IsCommandIdSupported(int command_id) {
  return command_id >= IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 &&
         command_id <= IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION_LAST;
}

bool StartSmartSelectionActionMenu::IsCommandIdChecked(int command_id) {
  return false;
}

bool StartSmartSelectionActionMenu::IsCommandIdEnabled(int command_id) {
  return true;
}

void StartSmartSelectionActionMenu::ExecuteCommand(int command_id) {
  if (!IsCommandIdSupported(command_id))
    return;

  size_t index = command_id - IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1;
  if (actions_.size() <= index)
    return;

  gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint();
  display::Display display =
      display::Screen::GetScreen()->GetDisplayNearestPoint(point);

  Profile* profile = Profile::FromBrowserContext(context_);
  apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithIntent(
      actions_[index].app_id, ui::EF_NONE,
      CreateIntent(std::move(actions_[index].action_intent),
                   std::move(actions_[index].activity)),
      apps::mojom::LaunchSource::kFromSmartTextContextMenu,
      apps::MakeWindowInfo(display.id()));
}

void StartSmartSelectionActionMenu::HandleTextSelectionActions(
    std::vector<TextSelectionActionDelegate::TextSelectionAction> actions) {
  actions_ = std::move(actions);

  for (size_t i = 0; i < actions_.size(); ++i) {
    proxy_->UpdateMenuItem(
        IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 + i,
        /*enabled=*/true,
        /*hidden=*/false,
        /*title=*/base::UTF8ToUTF16(actions_[i].title));

    proxy_->UpdateMenuIcon(
        IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 + i,
        ui::ImageModel::FromImageSkia(std::move(actions_[i].icon)));
  }

  for (size_t i = actions_.size(); i < kMaxMainMenuCommands; ++i) {
    // There were fewer actions returned than placeholder slots, remove the
    // empty menu item.
    proxy_->RemoveMenuItem(IDC_CONTENT_CONTEXT_START_SMART_SELECTION_ACTION1 +
                           i);
  }

  // The asynchronous nature of adding smart actions means that sometimes,
  // depending on whether actions were found and if extensions menu items were
  // added synchronously, there could be extra (adjacent) separators in the
  // context menu that must be removed once we've finished loading everything.
  proxy_->RemoveAdjacentSeparators();
}

}  // namespace arc
